package com.hippo.core.ui.compose.control

import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.alibaba.fastjson.JSONObject
import com.hippo.core.config.AppConsts
import com.hippo.core.core.ext.toJson
import com.hippo.core.state.ControlState
import com.hippo.core.tuya.DpInfo
import com.hippo.core.tuya.ThingControl
import com.hippo.core.tuya.toControlType
import com.hippo.core.tuya.toSpeedy
import com.hippo.core.utils.UiHandler
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.sdk.api.IDeviceListener
import com.thingclips.smart.sdk.api.IResultCallback
import com.thingclips.smart.sdk.api.IThingDevice
import com.thingclips.smart.sdk.api.WifiSignalListener
import com.thingclips.smart.sdk.enums.ThingDevicePublishModeEnum


class ControlVMFactory(private val devId: String) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(ControlVM::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return ControlVM(devId) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

class ControlVM(private val devId:String) :ViewModel() {

    private val thingDevice: IThingDevice = ThingHomeSdk.newDeviceInstance(devId)

    companion object{
        const val TAG = "ControlVM"
    }

    var uiState by mutableStateOf(ControlState(devId = devId))

    var historyControlType:Int = uiState.controlType

    fun updateState(state: ControlState){
        uiState = state
    }

    init {

        Log.d(TAG, "ControlVM: devId :  $devId")

        ThingControl.devId = devId

        thingDevice.registerDeviceListener(object : IDeviceListener{
            override fun onDpUpdate(devId: String, dpStr: MutableMap<String, Any>?) {

                Log.i(TAG, "onDpUpdate: ${dpStr.toJson()}")

//                if(dpStr != null && dpStr.containsKey("battery_percentage")){
//                    return
//                }

                updateDeviceState()

            }

            override fun onRemoved(devId: String?) {
                Log.d(TAG, "onRemoved: devId = $devId")
            }

            override fun onStatusChanged(devId: String?, online: Boolean) {
                Log.d(TAG, "onStatusChanged: devId = $devId, online = $online")
            }

            override fun onNetworkStatusChanged(devId: String?, status: Boolean) {
                Log.d(TAG, "onNetworkStatusChanged: devId = $devId, status = $status")
            }

            override fun onDevInfoUpdate(devId: String?) {
                Log.d(TAG, "onDevInfoUpdate: devId = $devId")
            }

        })

    }



    fun updateDeviceState(){

        val deviceValue = ThingControl.getDeviceValue(devId)
        val controlType = deviceValue.mode.toControlType()
        val speedy = deviceValue.suction.toSpeedy()

        if(controlType != AppConsts.ControlType.STANDBY){
            historyControlType = controlType
        }

        uiState = uiState.copy(
            isLoading = false,
            deviceValue = deviceValue,
            controlType = controlType,
            speedy = speedy
        )

        Log.d(TAG, "onDpUpdate updateDeviceState: ${uiState.deviceValue.toJson()}")
    }

    override fun onCleared() {
        super.onCleared()
        thingDevice.unRegisterDevListener()
        thingDevice.onDestroy()
    }





    fun getDevice(){
        val device = ThingControl.getDeviceBean()
        updateState(uiState.copy(device = device) )
    }



    fun publishDps(vararg dpInfos: DpInfo,showLoading:Boolean = false, successCallback:(()->Unit)? = null){

        if(showLoading){
            uiState = uiState.copy(isLoading = true)
        }

        val jsonObject = JSONObject()
        for( dpInfo in dpInfos){
            jsonObject[dpInfo.dpId] = dpInfo.dpValue
        }
        val dps = jsonObject.toString()

        Log.i(TAG, "publishDps: $dps")

        thingDevice.publishDps(dps, ThingDevicePublishModeEnum.ThingDevicePublishModeAuto,object : IResultCallback{
            override fun onError(code: String?, error: String?) {
                Log.e(TAG, "onError: code= $code  error= $error")
                UiHandler.showToast(error)
            }

            override fun onSuccess() {
                Log.i(TAG, "publishDps: onSuccess")
//                successCallback?.invoke()
//                updateDeviceState()
            }
        })
    }


    fun publishDps(dpId:String,value: Any){

        val jsonObject = JSONObject()
        jsonObject[dpId] = value
        val dps = jsonObject.toString()

        Log.i(TAG, "publishDps: $dps")

        thingDevice.publishDps(dps,object : IResultCallback{
            override fun onError(code: String?, error: String?) {
                Log.d(TAG, "onError: code= $code  error= $error")
                UiHandler.showToast(error)
            }

            override fun onSuccess() {
                Log.d(TAG, "publishDps: onSuccess")
            }
        })
    }


    fun getDeviceWifiSignal(){
        thingDevice.requestWifiSignal(
            object : WifiSignalListener {
                override fun onSignalValueFind(signal: String?) {
                    Log.d(TAG, "onSignalValueFind: $signal")
                    uiState.copy(wifiSignal = signal?.toInt()?:-100)
                }

                override fun onError(errorCode: String?, errorMsg: String?) {
                    Log.d(TAG, "onError: $errorMsg")
                }
            }
        )
    }


}